<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <script type="module">
        // generator的简单使用
        //-------------------------------------------------
        // function* gen() {
        //     const num1 = yield 1;
        //     console.log(num1);
        //     const num2 = yield 2;
        //     console.log(num2);
        //     return 3;
        // }
        // const g = gen();
        // console.log(g.next());//{value:1,done:false}
        // console.log(g.next(22));//22 {value:2,done:false} 
        // console.log(g.next(23));//23 {value:3,done:true}


        // Promise与generator结合使用实现async/await
        //-------------------------------------------------
        // 简易版例子:
        // function fn(num) {
        //     return new Promise((resolve, reject) => {
        //         setTimeout(function () {
        //             resolve(num*2);
        //         }, 1000)
        //     })
        // }
        // function* gen() {
        //     const num1 = yield fn(1);
        //     const num2 = yield fn(num1);
        //     const num3 = yield fn(num2);
        //     return num3;
        // }
        // const g = gen();
        // const next1 = g.next();
        // next1.value.then(res1 => {
        //     console.log(next1, res1);// {value: Promise, done: false} 2
        //     const next2 = g.next(res1);
        //     next2.value.then(res2 => {
        //         console.log(next2, res2);// {value: Promise, done: false} 4
        //         const next3 = g.next(res2);
        //         next3.value.then(res3 => {
        //             console.log(next3, res3);// {value: Promise, done: false} 8
        //         })
        //     })
        // })

        // 优化版(promise+generator)模拟async,await
        //-------------------------------------------------

        // const test = function () {

        //     return new Promise((resove0, reject0) => {

        //         setTimeout(() => {
        //             new Promise((resove1, reject1) => {
                       
        //                 setTimeout(() => {
                            
        //                            new Promise((resove2, reject2) => {

        //                             resove0("OK"); // 注意这里是resove0

        //                             });

        //                 }, 1000);
                    

        //         });
        //         },1000);
                

        //     });

        // }

        // test().then((data) => {
        //     alert(data);
        // });


        function fn(num) {
            return new Promise((resolve, reject) => {
                setTimeout(function () {
                    resolve(num * 2);
                }, 1000)
            })
        }
        function* gen() {
            const num1 = yield fn(1);
            const num2 = yield fn(num1);
            const num3 = yield fn(num2);
            return num3;
        }

        function genneratorToAsync(generatorFn) {
            return function () {
                const gen = generatorFn.apply(this, arguments);
                
                return new Promise(
                    (resolve, reject) => {
                        function go(key, arg) { // key :next; arg
                            let res;
                            try {
                                // key:"next" ;
                                // arg:null->""->"2"->"4"->"8"; 
                                // res:{value：Promise，true/false:boolean}
                                res = gen[key](arg); // gen是状态机 
                            } catch (err) {
                                // 这里加return 原因:resolve/reject只能改变promise的状态,
                                // 但是reject和resolve都无法让函数剩下的部分暂停执行
                                return reject(err)
                            }
                            // 解构
                            const { value, done } = res; // value:Promise  done:boolean

                            if (done) {
                                // value:Promise  done:true
                                // 这里加return 原因:resolve/reject只能改变promise的状态,
                                // 但是reject和resolve都无法让函数剩下的部分暂停执行
                                return resolve(value)
                            } else {
                                // value:Promise  done:false

                                // 递归方式实现不断的嵌套,避免嵌套地狱写法
                                value.then(
                                    (data) => {
                                        go('next', data);
                                    },
                                    (err) => {
                                        // 这里加return 原因:resolve/reject只能改变promise的状态,
                                        // 但是reject和resolve都无法让函数剩下的部分暂停执行
                                        return reject(err);
                                    }
                                )

                                // 递归方式实现不断的嵌套,避免嵌套地狱写法
                                // 这里加return 原因:resolve/reject只能改变promise的状态,
                                // 但是reject和resolve都无法让函数剩下的部分暂停执行
                                // Promise.resolve(value) 其实就是value:Promise 
                                // return Promise.resolve(value) 
                                // .then(
                                // val => go('next', val),
                                // err => go('throw', err)
                                // )
                            }
                        }
                        go('next')
                    })
            
                }
        }
 
        const x = genneratorToAsync(gen)("aa", "bb");//调用后返回一个promise对象,所有有then方法
        x.then(
            res => {
                console.log('优化版', res);// 8
            },
            (err) => {
                console.log('优化版', err);
            });

//
//-------------------------------------------------
// function fn(num) {
//     return new Promise((resolve, reject) => {
//         setTimeout(function () {
//             resolve(num*2);
//         }, 1000)
//     })
// }
// const genAsync = async function() {
//     const num1 = await fn(1);
//     const num2 = await fn(num1);
//     const num3 = await fn(num2);
//     return num3;
// }

// let x = genAsync();
// x.then((data)=>{
//     console.log(data);
// });

//
//-------------------------------------------------


    </script>
</head>

<body>

</body>

</html>